home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / PowerPlant / AGA Classes 1.2 / Utilities / LAGAPopupMenu.cp < prev    next >
Text File  |  1996-06-30  |  11KB  |  356 lines

  1. // ===========================================================================
  2. //    LAGAPopupMenu.cp
  3. // ===========================================================================
  4. //    
  5. //    Copyright © 1996 Chrisoft (Christophe ANDRES)  All rights reserved.
  6. //
  7. //    You may use this source code in any application (commercial, shareware, freeware,
  8. //    postcardware, etc), but not remove this notice (no need to acknowledge the use of
  9. //    this class in the about box)
  10. //    You may not sell this source code in any form. This source code may be placed on 
  11. //    publicly accessable archive sites and source code disks. It may not be placed on 
  12. //    profit archive sites and source code disks without the permission of the author, 
  13. //    Christophe ANDRES.
  14. //    
  15. //        This source code is distributed in the hope that it will be useful,
  16. //        but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. //        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  18. //
  19. //    If you make any change or improvement on this class, please send the improved/changed
  20. //    version to : chrisoft@calva.net or Christophe ANDRES
  21. //                                     20, rue Prosper Mérimée
  22. //                                     67100 STRASBOURG
  23. //                                     FRANCE
  24. //
  25. // ===========================================================================
  26. //    LAGAPopupMenu.h            <- double-click + Command-D to see class declaration
  27. //
  28. //    LAGAPopupMenu is simply a Popup menu class that works in windows with non white backgrounds.
  29. //    The standard Popup Menu CDEF erases in white its title, which in turn looks ugly if your
  30. //    background is NOT white.
  31. //
  32. //    Note:
  33. //        This class is called LAGAPopupMenu, because it was conceived to be used in conjunction with
  34. //        other “Apple Grayscale Appearance” classes, although it uses only the standard System 7
  35. //        Popup Menu CDEF and henceforth has NOT the look described in the AGA document.
  36. //
  37. //    Note:
  38. //        The use of this class is only necessary IF the Popup Menu you are using uses a title
  39. //
  40. //        This class requires AGAColors.cp to be present in your project
  41. //
  42. //        Version : 1.2
  43. //
  44. //        Change History (most recent first, date in US form : mm/dd/yy):
  45. //
  46. //                        06/30/96    ca        Public release of version 1.2
  47. //                        06/09/96    bp        Brad Pettit <bpettit@aimnet.com>
  48. //                                                        reimplemented using new StAGAEraseHack, since text alignment of the label
  49. //                                                        wasn't always correct for different fonts and label justification.
  50. //                        06/05/96    ca        Added RegisterClass method to ease registry
  51. //                                                        Increased version to 1.2
  52. //                        05/17/96    ca        Increased version to 1.1
  53. //                                                        Replaced UEnvironment::HasFeature(env_SupportsColor) with PaneInColor
  54. //                                                        Added change history
  55. //                        05/07/96    ca        class made available by Christophe ANDRES <chrisoft@calva.net>
  56. //                                                        (version 1.0)
  57. //
  58. //        To Do:
  59. //
  60.  
  61. #include "LAGAPopupMenu.h"
  62. #include "AGAColors.h"
  63.  
  64. //    begin    <06/09/96    bp>
  65. // Magic: this stack-based class sets up an alternate set of quickdraw procs
  66. // so that we can undo the lame side-effects of the standard pop-up control, which
  67. // ignores the port's background color when drawing itself.
  68. // When it performs an erase on a rectangle that intersects the area that is passed
  69. // to this objects constructor, we replace the background color with the specified
  70. // background color.
  71. // This class should not be created with new(), it should always be instantiated
  72. // on the stack. Nesting of these objects _may_ not do the right thing.
  73. // Possible Improvements: If qdProcs were already installed in this port, call them
  74. // instead of the original function.
  75. // -Contributed by Brad Pettit <bpettit@aimnet.com>
  76. class StAGAEraseHack
  77. {
  78.     public:
  79.     
  80.     StAGAEraseHack(LPane *inPane, const Rect& inAGARect, const RGBColor& inAGAColor);
  81.     
  82.     ~StAGAEraseHack();
  83.     
  84.     private:
  85.     
  86.     static pascal void RectFunction(GrafVerb verb, Rect *rect);
  87.     
  88.     Boolean    mWorking;
  89.     GrafPtr    mPort;
  90.     CQDProcs    mProcs;
  91.     QDProcs *mOldProcs;
  92.     RGBColor    mOldColor; // an attempt to support nesting
  93.     Rect        mOldRect; // an attempt to support nesting
  94.     
  95.     // we _could_ declare our own custom CQDProcs structure that has these
  96.     // members at the end. But this is easier, and only 14 bytes versus the extra complexity.
  97.     static Rect sOverrideRect;
  98.     static RGBColor sOverrideColor;
  99. };
  100.  
  101. Rect        StAGAEraseHack::sOverrideRect;
  102. RGBColor    StAGAEraseHack::sOverrideColor;
  103.  
  104. StAGAEraseHack::StAGAEraseHack (LPane* inPane, const Rect& inAGARect, const RGBColor& inAGAColor)
  105. {
  106.     mWorking = ::PaneInColor(inPane); // otherwise we don't need to do anything
  107.     
  108.     if (mWorking)
  109.         {
  110.             // save the old rectangle in case this is a nested occurrance of this object
  111.             mOldRect = sOverrideRect;
  112.             sOverrideRect = inAGARect;
  113.             
  114.             // and ditto on the color
  115.             mOldColor = sOverrideColor;
  116.             sOverrideColor = inAGAColor;
  117.             
  118.             // initialize the procs with the standard quickdraw procs
  119.             ::SetStdCProcs(&mProcs);
  120.             // and replace the rect function with ours
  121.             mProcs.rectProc = NewQDRectProc(RectFunction);
  122.             
  123.             ::GetPort(&mPort);
  124.             // save the original grafProcs
  125.             mOldProcs = mPort->grafProcs;
  126.             // and install our grafProcs
  127.             mPort->grafProcs = (QDProcs*) &mProcs;
  128.         }
  129. }
  130.  
  131. StAGAEraseHack::~StAGAEraseHack ()
  132. {
  133.     if(mWorking) // otherwise we didn't do anything
  134.         {
  135.             // restore the original grafProcs
  136.             mPort->grafProcs = (QDProcs*) mOldProcs;
  137.             // and free our routine descriptor
  138.             DisposeRoutineDescriptor(mProcs.rectProc);
  139.  
  140.             // restore the original color and rectangle in case we were nested.        
  141.             sOverrideColor = mOldColor;
  142.             sOverrideRect = mOldRect;
  143.         }
  144. }
  145.  
  146. // Magic: intercept the rect drawing calls and override the color
  147. // if we're performing an erase
  148. // static
  149. pascal void StAGAEraseHack::RectFunction (GrafVerb verb, Rect *rect)
  150. {
  151.     if(verb == kQDGrafVerbErase)
  152.         {
  153.             Rect scratch;
  154.             if(::SectRect(rect, &sOverrideRect, &scratch))
  155.                 ::RGBBackColor(&sOverrideColor);
  156.         }
  157.     
  158.     ::StdRect(verb, rect); // perform the original quickdraw function
  159. }
  160. //    end    <06/09/96    bp>
  161.  
  162. //    begin    <06/05/96    ca>
  163. void LAGAPopupMenu::RegisterClass ()
  164.  
  165. {
  166.     URegistrar::RegisterClass(LAGAPopupMenu::class_ID, (ClassCreatorFunc)LAGAPopupMenu::CreateAGAPopupMenuStream);
  167. }
  168. //    end    <06/05/96    ca>
  169.  
  170. LAGAPopupMenu* LAGAPopupMenu::CreateAGAPopupMenuStream (LStream *inStream)
  171.  
  172. {
  173.     return(new LAGAPopupMenu(inStream));
  174. }
  175.  
  176. LAGAPopupMenu::LAGAPopupMenu (LStream *inStream) : LStdControl(inStream)
  177.  
  178. {
  179.     Int16    initialMenuItem;
  180.     inStream->ReadData(&initialMenuItem, sizeof(Int16));
  181.     
  182.     InitAGAPopupMenu(initialMenuItem);
  183. }
  184.  
  185. LAGAPopupMenu::LAGAPopupMenu (const SPaneInfo &inPaneInfo, MessageT inValueMessage,
  186.                                                             Int16 inTitleOptions, ResIDT inMENUid, Int16 inTitleWidth,
  187.                                                             Int16 inPopupVariation, ResIDT inTextTraitsID, Str255 inTitle,
  188.                                                             OSType inResTypeMENU, Int16 inInitialMenuItem)
  189.                             : LStdControl(inPaneInfo, inValueMessage, inTitleOptions, inMENUid, inTitleWidth,
  190.                                                             inPopupVariation, inTextTraitsID, inTitle, inResTypeMENU)
  191. {
  192.     InitAGAPopupMenu(inInitialMenuItem);
  193. }
  194.  
  195.  
  196. void LAGAPopupMenu::DrawSelf()
  197.  
  198. {
  199.         // For some reason, after a Popup Menu moves, the Control Manager
  200.         // erases the old location of the Popup. All this happens within
  201.         // the Draw1Control() call to draw the Popup at its new location.
  202.         // To prevent this erasure, we restrict the clipping region to
  203.         // just the current location of the Popup.
  204. #ifdef NOT_DEFINED
  205.     Rect    frame;
  206.     CalcLocalFrameRect(frame);
  207.  
  208.     if (::PaneInColor(this))
  209.         {
  210.             frame.left += mTitleWidth;
  211.             {
  212.                 StClipRgnState    clip;
  213.                 clip.ClipToIntersection(frame);
  214.                 LStdControl::DrawSelf();
  215.             }
  216.             
  217.             Int16 just = UTextTraits::SetPortTextTraits(mTextTraitsID);
  218.             CalcLocalFrameRect(frame);
  219.             frame.right = frame.left + mTitleWidth;
  220.             ApplyForeAndBackColors();
  221.             ::EraseRect(&frame);
  222.             frame.left += 4;
  223.             frame.right -= 4;
  224.             FontInfo info;
  225.             ::GetFontInfo(&info);
  226.             frame.top += (((frame.bottom - frame.top) - (info.ascent + info.descent)) / 2) - 1;
  227.             Str255 theTitle;
  228.             GetDescriptor(theTitle);
  229.             {
  230.                 StClipRgnState    clip2;
  231.                 clip2.ClipToIntersection(frame);
  232.                 UTextDrawing::DrawWithJustification((Ptr)&theTitle[1], theTitle[0], frame, just);
  233.             }
  234.         }
  235.     else
  236.         {
  237.             //    If we have no color, then we leave everything to the real popup CDEF
  238.             StClipRgnState    clip;
  239.             clip.ClipToIntersection(frame);
  240.             LStdControl::DrawSelf();
  241.         }
  242. #else
  243.     //    begin    <06/09/96    bp>
  244.     StClipRgnState    clip;
  245.     Rect    frame;
  246.     CalcLocalFrameRect(frame);
  247.     clip.ClipToIntersection(frame);
  248.  
  249.     Rect title;
  250.     GetTitleRect(title);
  251.     StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
  252.  
  253.     LStdControl::DrawSelf();
  254.     //    end <06/09/96    bp>
  255. #endif /*NOT_DEFINED*/
  256. }
  257.  
  258. MenuHandle LAGAPopupMenu::GetMacMenuH ()
  259.  
  260. {
  261.     PopupPrivateDataHandle dataH = (PopupPrivateDataHandle)(**GetMacControl()).contrlData;
  262.     return (**dataH).mHandle;
  263. }
  264.  
  265. //    begin    <06/09/96    bp>
  266. // overridden because it draws the control as a side-effect
  267. Boolean LAGAPopupMenu::TrackHotSpot (Int16 inHotSpot, Point inPoint)
  268.  
  269. {
  270.     Boolean result = LStdControl::TrackHotSpot(inHotSpot, inPoint);
  271.  
  272.     // redraw the control, since TrackHotSpot left the background white
  273.     FocusDraw();
  274.     DrawSelf();
  275.     
  276.     return result;
  277. }
  278.  
  279. // overridden because it may draw the control as a side-effect
  280. void LAGAPopupMenu::SetValue (Int32 inValue)
  281.  
  282. {    
  283.     FocusDraw();
  284.  
  285.     Rect title;
  286.     GetTitleRect(title);
  287.     StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
  288.  
  289.     LStdControl::SetValue(inValue);
  290. }
  291.  
  292. // overridden because it may draw the control as a side-effect
  293. void LAGAPopupMenu::SetMaxValue (Int32 inValue)
  294.  
  295. {
  296.     FocusDraw();
  297.  
  298.     Rect title;
  299.     GetTitleRect(title);
  300.     StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
  301.  
  302.     LStdControl::SetMaxValue(inValue);
  303. }
  304.  
  305. // overridden because it may draw the control as a side-effect
  306. void LAGAPopupMenu::SetMinValue (Int32 inValue)
  307.  
  308. {
  309.     FocusDraw();
  310.  
  311.     Rect title;
  312.     GetTitleRect(title);
  313.     StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
  314.  
  315.     inherited::SetMinValue(inValue);
  316. }
  317.  
  318. void LAGAPopupMenu::GetTitleRect (Rect& outRect)
  319.  
  320. {
  321.     CalcLocalFrameRect(outRect);
  322.  
  323.     outRect.right = outRect.left + mTitleWidth;
  324. }
  325. //    end    <06/09/96    bp>
  326.  
  327. void LAGAPopupMenu::InitAGAPopupMenu (Int16 inInitialMenuItem)
  328.  
  329. {
  330.     mTitleWidth = mMaxValue;
  331.  
  332. //    begin    <06/09/96    bp>
  333. #ifdef NOT_DEFINED
  334.     // we don't use these. This is an example of how to
  335.     // extract the justification and style information for the title
  336.     mTitleJust = mValue & 0x000000ff; // low byte stores justification
  337.     mTitleStyle = ((mValue & 0x0000ff00) & ~popupTitleNoStyle) >> 8; // second byte stores style
  338. #endif /*NOT_DEFINED*/
  339. //    end    <06/09/96    bp>
  340.  
  341.         // Popups use the initial values for other purposes. Control Manager
  342.         // determines min/max from the size of the Menu. So now we have to
  343.         // adjust the value, min, and max stored by LControl.
  344.         
  345.     mValue = ::GetControlValue(mMacControlH);
  346.     mMinValue = ::GetControlMinimum(mMacControlH);
  347.     mMaxValue = ::GetControlMaximum(mMacControlH);    
  348.     
  349.     if (inInitialMenuItem != mValue)
  350.         {
  351.             ::SetControlValue(mMacControlH, inInitialMenuItem);
  352.             mValue = ::GetControlValue(mMacControlH);
  353.         }
  354. }
  355.  
  356.